package com.bstek.urule.console.servlet.variable;

import com.bstek.urule.ClassUtils;
import com.bstek.urule.Configure;
import com.bstek.urule.console.servlet.base.BaseController;
import com.bstek.urule.model.library.Datatype;
import com.bstek.urule.model.library.variable.Act;
import com.bstek.urule.model.library.variable.Variable;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.TypeReference;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 *
 * </p>
 *
 * @author zhouchaoliang
 * @since 2021/12/8
 */
@Controller
public class VariableEditorController extends BaseController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Value("${data-governance}")
    private String urlPropertise;

    @GetMapping("/urule/variableeditor")
    public ModelAndView variable(HttpServletRequest req, HttpServletResponse resp) {
        ModelAndView mv = new ModelAndView("/variable-editor");
        mv.addObject("contextPath", req.getContextPath());
        return mv;
    }

    @PostMapping(value = "/urule/variableeditor/importXml")
    public void importXml(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletContext servletContext = req.getSession().getServletContext();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        factory.setRepository(repository);
        ServletFileUpload upload = new ServletFileUpload(factory);
        InputStream inputStream=null;
        try {
            List<FileItem> items = upload.parseRequest(req);
            if(items.size()!=1){
                throw new ServletException("Upload xml file is invalid.");
            }
            FileItem item=items.get(0);
            inputStream=item.getInputStream();
            String xmlContent= IOUtils.toString(inputStream, "utf-8");
            List<Variable> variables=new ArrayList<Variable>();
            Document doc= DocumentHelper.parseText(xmlContent);
            Element root=doc.getRootElement();
            String clazz=root.attributeValue("clazz");
            for(Object obj:root.elements()){
                if(obj==null || !(obj instanceof Element)){
                    continue;
                }
                Element ele=(Element)obj;
                Variable var=new Variable();
                var.setAct(Act.InOut);
                var.setDefaultValue(ele.attributeValue("defaultValue"));
                var.setLabel(ele.attributeValue("label"));
                var.setName(ele.attributeValue("name"));
                var.setType(Datatype.valueOf(ele.attributeValue("type")));
                variables.add(var);
            }
            Map<String,Object> result=new HashMap<String,Object>();
            result.put("clazz", clazz);
            result.put("variables", variables);
            writeObjectToJson(resp, result);
        } catch (Exception e) {
            throw new ServletException(e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    @ResponseBody
    @PostMapping(value = "/urule/variableeditor/generateFields")
    public List<Variable> generateFields(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String clazz=req.getParameter("clazz");
        try {
            return ClassUtils.classToVariables(Class.forName(clazz));
        } catch (ClassNotFoundException e) {
            return classToVariables(clazz);
        }
    }

    private List<Variable> classToVariables(String clazz) throws ServletException{

        List<ServiceInstance> sis = discoveryClient.getInstances("data-governance");

        String urlStr = null;
        if(null != sis && sis.size() > 0){
            urlStr = sis.get(0).getUri().toString();
        }else{
            urlStr = urlPropertise;
        }

        HttpURLConnection connection=null;
        try{
            String clientUrl=urlStr + "/urule/variableeditor/generateFields?clazz="+clazz;
            URL url=new URL(clientUrl);
            connection=(HttpURLConnection)url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Charset", "UTF-8");
            connection.setRequestProperty("Accept-Charset", "utf-8");
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setUseCaches(false);
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.connect();
            if (connection.getResponseCode() >= 300) {
                throw new ServletException("生成失败");
            }
            InputStream inputStream=connection.getInputStream();

            ObjectMapper mapper=new ObjectMapper();
            mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
            mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS,false);
            mapper.setDateFormat(new SimpleDateFormat(Configure.getDateFormat()));
            List<Variable> variables = mapper.readValue(inputStream,new TypeReference<List<Variable>>(){});

            inputStream.close();

            return variables;
        }catch(Exception ex){
            ex.printStackTrace();
            throw new ServletException("生成失败");
        }finally {
            if(connection!=null){
                connection.disconnect();
            }
        }
    }
}
